#include "OpenGLWidget.h"

OpenGLWidget::OpenGLWidget(QWidget* parent /*= 0*/) : QOpenGLWidget(parent)
, mGraphicsWindow(new osgViewer::GraphicsWindowEmbedded(this->x(), this->y(),
	this->width(), this->height())),
	mViewer(new osgViewer::Viewer)
	, mRoot(new osg::Group())
{
	setMouseTracking(true);

	initData();

	initCamera();

	initViewer();
}

OpenGLWidget::~OpenGLWidget()
{
}

osg::Group* OpenGLWidget::getData()
{
	return mViewer->getSceneData()->asGroup();
}

osg::Group* OpenGLWidget::getRoot()
{
	return mRoot;
}

void OpenGLWidget::setViewOrientation(ORIENTATION ori)
{
	const osg::BoundingSphere& boundingSphere = getData()->getBound();

	osg::Vec3f eye;
	osg::Vec3f center = boundingSphere.center();
	osg::Vec3f up;

	

	switch (ori)
	{
	case ORIENTATION::TOP_VIEW:
		eye = boundingSphere.center() + osg::Z_AXIS * boundingSphere.radius()*3.5;
		up = osg::Y_AXIS;
		break;
	case ORIENTATION::BOTTOM_VIEW:
		eye = boundingSphere.center() + osg::Z_AXIS*-1.0 * boundingSphere.radius()*3.5;
		up = osg::Y_AXIS*-1.0;
		break;
	case ORIENTATION::FRONT_VIEW:
		eye = boundingSphere.center() + osg::Y_AXIS*-1.0 * boundingSphere.radius()*3.5;
		up = osg::Z_AXIS;
		break;
	case ORIENTATION::BACK_VIEW:
		eye = boundingSphere.center() + osg::Y_AXIS * boundingSphere.radius()*3.5;
		up = osg::Z_AXIS;
		break;
	case ORIENTATION::LEFT_VIEW:
		eye = boundingSphere.center() + osg::X_AXIS*-1.0 * boundingSphere.radius()*3.5;
		up = osg::Z_AXIS;
		break;
	case ORIENTATION::RIGHT_VIEW:
		eye = boundingSphere.center() + osg::X_AXIS * boundingSphere.radius()*3.5;
		up = osg::Z_AXIS;
		break;
	case ORIENTATION::FIT_VIEW:
		mViewer->getCamera()->getViewMatrixAsLookAt(eye, center, up);
		eye = boundingSphere.center() + (eye - center)*boundingSphere.radius()*3.5;
		center = boundingSphere.center();
	default:
		break;
	}

	osgGA::StandardManipulator* manipulator = static_cast<osgGA::StandardManipulator*>(mViewer->getCameraManipulator());

	if ( manipulator)
	{
		manipulator->setTransformation(eye, center, up);
	}
}

void OpenGLWidget::initData()
{
	osg::Group* root = new osg::Group();
	root->setName("root");
	mViewer->setSceneData(root);

	mAxes = new Axes;
	mAxes->setName("axes");
	mAxes->setCamera(mViewer->getCamera());
	getData()->addChild(mAxes);
	getData()->addChild(mRoot);
}

void OpenGLWidget::initCamera()
{
	osg::Camera* camera = mViewer->getCamera();
	camera->setViewport(0, 0, width(), height());
	camera->setClearColor(osg::Vec4(0.54, 0.81, 0.94, 1.0));
	camera->setProjectionMatrixAsPerspective(30.f, static_cast<float>(width()) / static_cast<float>(height()), 1.f, 1000.f);
	camera->setGraphicsContext(mGraphicsWindow);
}

void OpenGLWidget::initViewer()
{
	osgGA::TrackballManipulator* manipulator = new osgGA::TrackballManipulator;
	manipulator->setAllowThrow(false);
	manipulator->setHomePosition(osg::Vec3(0, 0, 1000), osg::Vec3(0, 0, 0), osg::Vec3(0, 1, 0));

	mViewer->setCameraManipulator(manipulator);
	mViewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
	mViewer->realize();
}

void OpenGLWidget::initializeGL()
{
	osg::Group* root = getData();
	osg::StateSet* stateSet = root->getOrCreateStateSet();
	osg::Material* material = new osg::Material;
	material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
	stateSet->setAttributeAndModes(material, osg::StateAttribute::ON);
	stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
}

void OpenGLWidget::resizeGL(int w, int h)
{
	this->getEventQueue()->windowResize(this->x(), this->y(), w, h);
	mGraphicsWindow->resized(this->x(), this->y(), w, h);
	osg::Camera* camera = mViewer->getCamera();
	camera->setViewport(0, 0, this->width(), this->height());
}

void OpenGLWidget::paintGL()
{
	mViewer->frame();
}

void OpenGLWidget::mouseMoveEvent(QMouseEvent* event)
{
	this->getEventQueue()->mouseMotion(event->x(), event->y());
}

void OpenGLWidget::mousePressEvent(QMouseEvent* event)
{
	unsigned int button = 0;
	switch (event->button()) {
	case Qt::LeftButton:
		button = 1;
		break;
	case Qt::MiddleButton:
		button = 2;
		break;
	case Qt::RightButton:
		button = 3;
		break;
	default:
		break;
	}
	this->getEventQueue()->mouseButtonPress(event->x(), event->y(), button);
}

void OpenGLWidget::mouseReleaseEvent(QMouseEvent* event)
{
	unsigned int button = 0;
	switch (event->button()) {
	case Qt::LeftButton:
		button = 1;
		break;
	case Qt::MiddleButton:
		button = 2;
		break;
	case Qt::RightButton:
		button = 3;
		break;
	default:
		break;
	}
	this->getEventQueue()->mouseButtonRelease(event->x(), event->y(), button);
}

void OpenGLWidget::wheelEvent(QWheelEvent* event)
{
	int delta = event->delta();
	osgGA::GUIEventAdapter::ScrollingMotion motion = delta > 0 ?
		osgGA::GUIEventAdapter::SCROLL_UP : osgGA::GUIEventAdapter::SCROLL_DOWN;
	this->getEventQueue()->mouseScroll(motion);
}

bool OpenGLWidget::event(QEvent* event)
{
	bool handled = QOpenGLWidget::event(event);
	this->update();
	return handled;
}

osgGA::EventQueue* OpenGLWidget::getEventQueue() const
{
	osgGA::EventQueue* eventQueue = mGraphicsWindow->getEventQueue();
	return eventQueue;
}